<?php

/**
 * @copyright Michiel Hakvoort 2010
 * @license http://www.opensource.org/licenses/bsd-license.php New BSD
 * @package mangrove
 * @subpackage groove
 * @filesource
 */

/*
 * Copyright (c) 2010 Michiel Hakvoort
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 * 3. The name of the author may not be used to endorse or promote products
 *    derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 */

namespace mg;

interface ASTVisitor {

    public function visitTemplet(TempletAST $templet);
    public function visitSequentialCommand(SequentialCommandAST $sequentialCommand);
    public function visitTextCommand(TextCommandAST $textCommand);
    public function visitSymbol(SymbolAST $symbol);
    public function visitTranslate(TranslateAST $translate);
    public function visitVariableExpression(VariableExpressionAST $variableExpression);
    public function visitFilterExpression(FilterExpressionAST $filterExpression);
    public function visitMethodExpression(MethodExpressionAST $methodExpression);
    public function visitScope(ScopeAST $scope);
    public function visitCache(CacheAST $cache);
    public function visitPhp(PhpAST $php);
    public function visitIf(IfAST $if);
    public function visitForeach(ForeachAST $foreach);
    public function visitPhpEcho(PhpEchoAST $phpEcho);

    public function visitRule(RuleAST $rule);
    public function visitMatch(MatchAST $match);

}

abstract class AST {

    public abstract function visit(ASTVisitor $visitor);
}

class TempletAST extends AST {

    /**
     * Enter description here...
     *
     * @var CommandAST
     */
    public $command = null;
    /**
     * Enter description here...
     *
     * @var RuleAST
     */
    public $rule = null;

    public $namespace = null;

    public $uses = null;

    public $contextImports = null;
    public function __construct(CommandAST $command = null, RuleAST $rule, $namespace, $uses, $contextImports) {
        $this->command = $command;
        $this->rule = $rule;

        if(mb_strlen($namespace) > 0 && mb_substr($namespace, -1) === '\\') {
            $namespace = mb_substr($namespace, 0, -1);
        }

        $this->namespace = $namespace;
        $this->uses = $uses;
        $this->contextImports = $contextImports;

    }

    public function visit(ASTVisitor $visitor) {
        return $visitor->visitTemplet($this);
    }
}

class RuleAST extends AST {

    /**
     * Enter description here...
     *
     * @var MatchAST
     */
    public $match = null;
    /**
     * Enter description here...
     *
     * @var RuleAST
     */
    public $nextRule = null;

    public function __construct(MatchAST $match, RuleAST $nextRule = null) {
        $this->match = $match;
        $this->nextRule = $nextRule;
    }

    public function visit(ASTVisitor $visitor) {
        return $visitor->visitRule($this);
    }
}

class MatchAST extends AST {
    /**
     * Enter description here...
     *
     * @var string
     */
    public $variable = null;
    /**
     * Enter description here...
     *
     * @var string
     */
    public $class    = null;
    /**
     * Enter description here...
     *
     * @var MatchAST
     */
    public $nextMatch = null;

    public function __construct($variable, $class, MatchAST $nextMatch = null) {
        $this->variable = $variable;
        $this->class = $class;
        $this->nextMatch = $nextMatch;
    }

    public function visit(ASTVisitor $visitor) {
        return $visitor->visitMatch($this);
    }
}

abstract class CommandAST extends AST {

}

class SequentialCommandAST extends CommandAST {

    /**
     * Enter description here...
     *
     * @var CommandAST
     */
    public $first;
    /**
     * Enter description here...
     *
     * @var CommandAST
     */
    public $second;

    public function __construct(CommandAST $first, CommandAST $second) {
        $this->first = $first;
        $this->second = $second;
    }

    public function visit(ASTVisitor $visitor) {
        return $visitor->visitSequentialCommand($this);
    }
}

class TextCommandAST extends CommandAST {

    /**
     * Enter description here...
     *
     * @var string
     */
    public $text;

    public function __construct($text) {
        $this->text = $text;
    }

    public function visit(ASTVisitor $visitor) {
        return $visitor->visitTextCommand($this);
    }
}

class SymbolAST extends AST {

    /**
     * Enter description here...
     *
     * @var SymbolAST
     */
    public $symbol = null;

    public function __construct($symbol) {
        $this->symbol = $symbol;
    }

    public function visit(ASTVisitor $visitor) {
        return $visitor->visitSymbol($this);
    }
}

abstract class ExpressionAST extends CommandAST {

}

class TranslateAST extends ExpressionAST {

    /**
     * Enter description here...
     *
     * @var AST
     */
    public $lookup = null;
    /**
     * Enter description here...
     *
     * @var array
     */
    public $parameters = null;

    public function __construct(AST $lookup, $parameters) {
        $this->lookup = $lookup;
        $this->parameters = $parameters;
    }

    public function visit(ASTVisitor $visitor) {
        return $visitor->visitTranslate($this);
    }
}

class VariableExpressionAST extends ExpressionAST {

    /**
     * Enter description here...
     *
     * @var string
     */
    public $variable;

    public function __construct($variable) {
        $this->variable = $variable;
    }

    public function visit(ASTVisitor $visitor) {
        return $visitor->visitVariableExpression($this);
    }
}

class FilterExpressionAST extends ExpressionAST {

    /**
     * Enter description here...
     *
     * @var ExpressionAST
     */
    public $expression;
    /**
     * Enter description here...
     *
     * @var string
     */
    public $filter;
    /**
     * Enter description here...
     *
     * @var array
     */
    public $parameters;

    public function __construct(ExpressionAST $expression, $filter, $parameters) {
        $this->expression = $expression;
        $this->filter = $filter;
        $this->parameters = $parameters;
    }

    public function visit(ASTVisitor $visitor) {
        return $visitor->visitFilterExpression($this);
    }
}

class MethodExpressionAST extends ExpressionAST {

    /**
     * Enter description here...
     *
     * @var CommandAST
     */
    public $expression;

    /**
     * Enter description here...
     *
     * @var string
     */
    public $method;
    /**
     * Enter description here...
     *
     * @var array
     */
    public $parameters;

    public function __construct(ExpressionAST $expression, $method, $parameters) {
        $this->expression = $expression;
        $this->method = $method;
        $this->parameters = $parameters;
    }

    public function visit(ASTVisitor $visitor) {
        return $visitor->visitMethodExpression($this);
    }
}

class ScopeAST extends CommandAST {

    /**
     * Enter description here...
     *
     * @var CommandAST
     */
    public $command;
    /**
     * Enter description here...
     *
     * @var array
     */
    public $scope;

    public function __construct(CommandAST $command = null, $scope) {
        $this->command = $command;
        $this->scope = $scope;
    }

    public function visit(ASTVisitor $visitor) {
        return $visitor->visitScope($this);
    }
}

class CacheAST extends CommandAST {

    /**
     * Enter description here...
     *
     * @var CommandAST
     */
    public $command;

    /**
     * Enter description here...
     *
     * @var array
     */
    public $duration;

    /**
     * Enter description here...
     *
     * @var array
     */
    public $key;

    public function __construct(CommandAST $command = null, $duration, $key) {
        $this->command = $command;
        $this->duration = $duration;
        $this->key = $key;
    }

    public function visit(ASTVisitor $visitor) {
        return $visitor->visitCache($this);
    }
}

class PhpAST extends CommandAST {

    /**
     * Enter description here...
     *
     * @var array
     */
    public $tokens;

    public function __construct($tokens) {
        $this->tokens = $tokens;
    }

    public function visit(ASTVisitor $visitor) {
        return $visitor->visitPhp($this);
    }
}

class IfAST extends CommandAST {

    /**
     * Enter description here...
     *
     * @var array
     */
    public $condition;

    /**
     * Enter description here...
     *
     * @var CommandAST
     */
    public $command;

    /**
     * Enter description here...
     *
     * @var CommandAST
     */
    public $else;

    public function __construct($condition, CommandAST $command = null, CommandAST $else = null) {
        $this->condition = $condition;
        $this->command = $command;
        $this->else = $else;
    }

    public function visit(ASTVisitor $visitor) {
        return $visitor->visitIf($this);
    }
}

class ForeachAST extends CommandAST {


    /**
     * Enter description here...
     *
     * @var array
     */
    public $condition;

    /**
     * Enter description here...
     *
     * @var CommandAST
     */
    public $command;

    public $else;

    public function __construct($condition, CommandAST $command = null, CommandAST $else = null) {
        $this->condition = $condition;
        $this->command = $command;
        $this->else = $else;
    }

    public function visit(ASTVisitor $visitor) {
        return $visitor->visitForeach($this);
    }
}

class PhpEchoAST extends CommandAST {

    /**
     * Enter description here...
     *
     * @var array
     */
    public $tokens;

    public function __construct($tokens) {
        $this->tokens = $tokens;
    }

    public function visit(ASTVisitor $visitor) {
        return $visitor->visitPhpEcho($this);
    }
}